﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DataStructures
{
	public class Tree<Element> : ITree<Element>
	{
		#region ctors
		public Tree(Element value, ITree<Element> parent, ITreeList<Element> children)
		{
			Value = value;
			Parent = parent;
			_Children = (children != null) ? children : new TreeList<Element>();
			_Children.Parent = this;

			_Trees = new TreeEnumerable<Element, ITree<Element>, ITreeList<Element>>(this);
			_Elements = new ElementEnumerable<Element, ITree<Element>, ITreeList<Element>>(this);
		}
		public Tree() : this(default(Element), null, null) { }
		public Tree(Element value) : this(value, null, null) { }
		public Tree(ITree<Element> parent) : this(default(Element), parent, null) { }
		public Tree(ITreeList<Element> children) : this(default(Element), null, children) { }
		#endregion ctors

		#region props
		public bool HasParent { get { return Parent != null; } }
		public bool HasChildren { get { return _Children != null && _Children.Count > 0; } }
		public ITree<Element> Parent
		{
			get { return _Parent; }
			set
			{
				if (value == _Parent)
					return;

				if (_Parent != null)
					_Parent.Children.Remove(this);

				if (value != null && !value.Children.Contains(this))
					value.Children.Add(this);

				_Parent = value;
			}
		}
		public ITree<Element> Root { get { return (Parent == null) ? this : Parent.Root; } }
		public ITreeList<Element> Children { get { return _Children; } }
		public Element Value { get; set; }
		public TraversalType TraversalType { get; set; }
		public virtual int Depth { get { return (Parent == null ? -1 : Parent.Depth) + 1; } }
		public virtual int Leaves
		{
			get
			{
				int count = 1;
				if (Children != null && Children.Count > 0)
				{
					count = 0;
					foreach (ITree<Element> child in Children)
						count += child.Leaves;
				}
				return count;
			}
		}
		public IBaseEnumerable<Element, ITree<Element>, ITreeList<Element>, ITree<Element>> Trees { get { return _Trees; } }
		public IBaseEnumerable<Element, ITree<Element>, ITreeList<Element>, Element> Elements { get { return _Elements; } }
		#endregion props

		#region methods
		public void Clear()
		{
			foreach (ITree<Element> child in Trees)
				child.Clear();
			Children.Clear();
		}
		public override string ToString()
		{
			string description = "[" + (Value == null ? "<null>" : Value.ToString()) + "] ";

			description += "Depth=" + Depth.ToString() + ", Children=" + Children.Count.ToString();

			if (Root == this)
				description += " (Root)";

			return description;
		}
		#endregion methods

		#region fields
		private ITree<Element> _Parent;
		private ITreeList<Element> _Children;

		private IBaseEnumerable<Element, ITree<Element>, ITreeList<Element>, ITree<Element>> _Trees;
		private IBaseEnumerable<Element, ITree<Element>, ITreeList<Element>, Element> _Elements;
		#endregion fields
	}
}
